#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sqlite3.h> //for sqlite3_open ..
#include <signal.h>
#include <time.h>//--------
#define PATH_DICT "./dict.txt" //单词表
#define PATH_DATA "./mydict.db" //数据库
#define N 32
#define M 128
#define R 0x1 //注册
#define L 0x2 //登录
#define Q 0x3  //查询单词
#define H 0x4  //历史记录
#define E 0x5 //退出

typedef struct{
	int type;//消息类型
	char name[N];//用户名
	char text[M];//单词  或 密码
}MSG;
#define LEN_SMG sizeof(MSG)
#define err_log(log)\
	do{\
	 perror(log);\
	 exit(1);\
	}while(0)

typedef struct sockaddr SA;
void process_register(int clientfd,MSG *msg,sqlite3 *db);
void process_login(int clientfd,MSG *msg,sqlite3 *db);
void process_query(int clientfd,MSG *msg,sqlite3 *db);
void process_history(int clientfd,MSG *msg,sqlite3 *db);
void insert_history(MSG *msg,sqlite3 *db);
void get_time(const char *date);
void handler(int arg)
{
	wait(NULL);
}
int main(int argc, const char *argv[])
{
	int serverfd,clientfd;
	struct sockaddr_in serveraddr,clientaddr;
	socklen_t len=sizeof(SA);
	int cmd;
	char clean[M]={0};
	MSG msg;
	pid_t pid;
	sqlite3 *db;
	ssize_t bytes;
	if(argc!=3)
	{
		fprintf(stderr,"User:%s <IP> <port>",argv[0]);
		return -1;
	}

	if(sqlite3_open(PATH_DATA,&db)!=SQLITE_OK)
	{
			printf("%s\n",sqlite3_errmsg(db));
			return -1;
	}
	if((serverfd=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		err_log("fail to socket");
	}
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(atoi(argv[2]));
	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
	if(bind(serverfd,(SA*)&serveraddr,len)<0)
	{
		err_log("fail to bind");
	}
	if(listen(serverfd,10)<0)
	{
		err_log("fail to listen");
	}
 	signal(SIGCHLD,handler);//处理僵尸进程

	while(1)
	{
		if((clientfd=accept(serverfd,(SA*)&clientaddr,&len))<0)
		{
			perror("fail to accept");
			continue;
		}
		pid=fork();
		if(pid<0)
		{
			perror("fail to fork");
			continue;
		}
		else if(pid==0)
		{
			close(serverfd);
			while(1)
			{
				bytes=recv(clientfd,&msg,LEN_SMG,0);
				printf("%s\n",msg.name);
				//--exit(0);
				if(bytes<=0)
					break;
				switch(msg.type)
				{
					case R:
						process_register(clientfd,&msg,db);
						break;
					case L:
						process_login(clientfd,&msg,db);
						break;
					case Q:
						process_query(clientfd,&msg,db);
						break;
					case H:
						process_history(clientfd,&msg,db);
						break;
				}
			}
			close(clientfd);
			exit(1);
		}
		else
		{
			close(clientfd);
		}


	}
	
	return 0;
}
void process_register(int clientfd,MSG *msg,sqlite3 *db)
{
	char sql[128] = {0};
	char **rep;
	char *errmsg;
	char buf[32] = {0};
	sprintf(sql,"insert into user values('%s','%s')",msg->name,msg->text);
	if( sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK )
	{
		printf("%s\n",errmsg);
		puts("insert fail!");
		strcpy(buf,"insert fail!");
		send(clientfd,buf,32,0);
		return;
	}
	else
	{
		puts("insert ok!");
		strcpy(buf,"insert_ok!");
		send(clientfd,buf,32,0);
		return ;
	}
	exit(0);
}
void process_login(int clientfd,MSG *msg,sqlite3 *db)
{
	char buf[32] = {0};
	char sql[128] = {0};
	char *errmsg;
	char **rep;
	int n_row,n_column,i,j;
	sprintf(sql,"select * from user where name='%s' and pwd='%s'",msg->name,msg->text);
	if( sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg) != SQLITE_OK)
	{
		printf("%s\n",errmsg);
		puts("query fail!");
		return ;
	}
	else
	{
		if( n_row== 0 )
		{
			printf("login fail!\n");
			strcpy(buf,"login fail!");
			send(clientfd,buf,32,0);
		}
		else
		{
			printf("login success!\n");
			strcpy(buf,"login success!");
			send(clientfd,buf,32,0);
		}
	}
}
void process_query(int clientfd,MSG *msg,sqlite3 *db)
{
	time_t t;
	struct tm* tmp;
	char timebuf[128] = {0};
	char sql[128]={0};
	time(&t);
	tmp = localtime(&t);	
	sprintf(timebuf,"%d-%d-%d %d:%d:%d",tmp->tm_year+1900,tmp->tm_mon+1,tmp->tm_mday,tmp->tm_hour,tmp->tm_min,tmp->tm_sec);
	printf("input query;\n");
	FILE *fp;
	char buf[1024]={0};
	char *errmsg;
	int len = strlen(msg->text);
	printf("%s\n%s\n",msg->name,msg->text);
	if((fp = fopen("./dict.txt","r")) == NULL)
	{
		printf("fopen fail!");
		return ;
	}
	while(fgets(buf,1024,fp) != NULL)
	{
		if(strncmp(buf,msg->text,len) == 0)
		{
			puts(buf);
			send(clientfd,buf+len,sizeof(buf),0);
			//insert History
			sprintf(sql,"insert into record values('%s','%s','%s')",msg->name,msg->text,timebuf);
			if( sqlite3_exec(db,sql,NULL,NULL,&errmsg) != SQLITE_OK)
			{
				printf("%s\n",errmsg);
				puts("insert record fail!");
				return ;
			}
			else
			{
				puts("insert record ok!");
				return ;
			}
		}
		bzero(buf,sizeof(buf));
	}
	send(clientfd,"no data!",8,0);

	

}
/*
void insert_history(MSG *msg,sqlite3 *db)
{
}
void get_time(const char *date)
{
}
*/
void process_history(int clientfd,MSG *msg,sqlite3 *db)
{
	char sql[128]={0};
	char buf[32]={0};
	char *errmsg;
	char **rep;
	int n_row;
	int n_column;
	int i,j;
	sprintf(sql,"select * from record where name='%s'",msg->name);
	if( sqlite3_get_table(db,sql,&rep,&n_row,&n_column,&errmsg) != SQLITE_OK)
	{
		printf("%s\n",errmsg);
		puts("query fail!");
		send(clientfd,"Fail",4,0);
		return ;
	}
	else
	{
		if( n_row == 0 )
		{
			puts("no record");
			send(clientfd,"NO",2,0);
			return ;
		}
		else
		{
			send(clientfd,"OK",2,0);
			for(i=0;i<n_row+1;i++)
			{
				for(j=0;j<n_column;j++)
				{
					sprintf(buf,"%s",*rep++);
					send(clientfd,buf,sizeof(buf),0);
					bzero(buf,sizeof(buf));
				}
			}
			send(clientfd,"&&",2,0);
		}
	}
}
